package dao

import (
	"chat_srv/basic/config"
	chat "chat_srv/basic/proto"
	"chat_srv/handler/model"
	"chat_srv/untils"
	"context"
	"fmt"
	"log"
	"sort"
	"strconv"
	"time"
)

// 创建群聊
func CreateGroupMessage(_ context.Context, in *chat.CreateGroupMessageReq) (*model.ImGroup, error) {
	// 参数校验
	if in.OwnerId == 0 || in.GroupName == "" {
		return nil, fmt.Errorf("参数不完整")
	}
	// 调用雪花算法生成群聊ID
	groupID := untils.GenerateGroupID()
	// 生成会话id
	conversationId := GenerateConversationId(int64(groupID), int64(in.OwnerId), config.ConversationTypeGroup)

	// 开启事务
	tx := config.DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()
	// 创建群聊
	group := &model.ImGroup{
		GroupId:        strconv.FormatInt(groupID, 10),
		ConversationId: conversationId,
		GroupName:      in.GroupName,
		GroupAvatar:    in.GroupAvatar,
		Announcement:   in.Announcement,
		OwnerId:        uint(in.OwnerId),
		MaxMembers:     uint(in.MaxMembers),
		Status:         1,
		CreatedAt:      time.Now(),
		UpdatedAt:      time.Now(),
	}
	if err := tx.Create(group).Error; err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("创建群聊失败：%v", err)
	}

	// 添加创建者为群主
	groupMember := &model.ImGroupMember{
		GroupId:        strconv.FormatInt(groupID, 10),
		UserId:         uint(in.OwnerId),
		Role:           3, // 群主
		MemberNickname: in.OwnerName,
		JoinedAt:       time.Now(),
		CreatedAt:      time.Now(),
	}
	if err := tx.Create(groupMember).Error; err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("添加群主失败：%v", err)
	}

	// 更新群聊成员数量
	group.MemberCount++
	if err := tx.Model(&model.ImGroup{}).Where("group_id = ?", group.GroupId).
		Update("member_count", group.MemberCount).Error; err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("更新群聊成员数量失败：%v", err)
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		return nil, fmt.Errorf("提交事务失败：%v", err)
	}

	return group, nil
}

// 查询或创建回话
func GetOrCreateGroupConversation(conversationId string, groupID string) (model.ImConversation, error) {
	// 查询现有的群会话
	var conversation model.ImConversation
	err := conversation.GetImConversation(conversationId)
	if err != nil {
		return model.ImConversation{}, fmt.Errorf("查询群会话失败: %w", err)
	}

	if conversation.Id == 0 {
		// 创建新的群会话
		return CreateGroupConversation(conversationId, groupID)
	}

	return conversation, nil
}

// 创建会话
func CreateGroupConversation(conversationId string, groupID string) (model.ImConversation, error) {
	// 查询群成员数
	var group model.ImGroup
	if err := group.GetImGroup(&model.ImGroup{GroupId: groupID}); err != nil {
		return model.ImConversation{}, fmt.Errorf("获取群聊失败：%v", err)
	}
	conversation := model.ImConversation{
		ConversationId:   conversationId,
		ConversationType: config.ConversationTypeGroup, // 群聊
		MemberCount:      group.MemberCount,            // 初始为1，实际成员数从群成员表获取
		CreatedAt:        time.Now(),
		UpdatedAt:        time.Now(),
	}

	if err := conversation.Create(config.DB); err != nil {
		return model.ImConversation{}, fmt.Errorf("创建群会话失败: %w", err)
	}

	return conversation, nil
}

// 发送群聊消息
func SendGroupMessage(_ context.Context, in *chat.SendGroupMessageReq) (*model.ImMessage, error) {
	// 参数校验
	if in.GroupId == "" || in.SenderId == 0 || in.Content == "" {
		return nil, fmt.Errorf("参数不完整")
	}

	// 验证用户是否在群聊中
	var imGroupMember model.ImGroupMember
	if err := imGroupMember.GetImGroupMember(&model.ImGroupMember{UserId: uint(in.SenderId)}); err != nil {
		return nil, fmt.Errorf("查询群成员失败：%v", err)
	}
	if imGroupMember.Id == 0 {
		return nil, fmt.Errorf("用户不在群聊中")
	}

	// 获取会话id
	var group model.ImGroup
	if err := group.GetImGroup(&model.ImGroup{GroupId: in.GroupId}); err != nil {
		return nil, fmt.Errorf("获取群聊失败：%v", err)
	}

	// 查询或创建群聊会话
	conversation, err := GetOrCreateGroupConversation(group.ConversationId, in.GroupId)
	if err != nil {
		return nil, fmt.Errorf("查询或创建群聊会话失败：%v", err)
	}

	// 生成消息序列号
	seq, err := GenerateSeq(group.ConversationId)
	if err != nil {
		return nil, fmt.Errorf("生成消息序列号失败：%v", err)
	}

	// 创建群消息
	groupMessage := &model.ImMessage{
		ConversationId: group.ConversationId,
		FormUserId:     uint(in.SenderId),
		ToTargetId:     in.GroupId,
		Content:        in.Content,
		MessageType:    uint(in.MessageType),
		Status:         config.MessageStatusDelivered, // 已发送
		Seq:            uint(seq),
		SendTime:       time.Now(),
		CreatedAt:      time.Now(),
	}
	// 保存群消息
	if err = groupMessage.Create(); err != nil {
		return nil, fmt.Errorf("保存群消息失败：%v", err)
	}

	// 更新会话最后消息
	lastMessage := map[string]interface{}{
		"last_message_id": groupMessage.Id,
		"last_seq":        groupMessage.Seq,
		"updated_at":      time.Now(),
	}
	if err = conversation.Update(group.ConversationId, lastMessage); err != nil {
		log.Printf("更新会话失败: %v", err)
	}

	return groupMessage, nil
}

// 加入群聊
func JoinGroup(_ context.Context, in *chat.JoinGroupReq) (*model.ImGroup, error) {
	// 判断群聊是否存在
	var group model.ImGroup
	if err := group.GetImGroup(&model.ImGroup{GroupId: in.GroupId}); err != nil {
		return nil, fmt.Errorf("获取群聊失败：%v", err)
	}
	if group.Id == 0 {
		return nil, fmt.Errorf("当前群聊不存在或已解散")
	}

	// 判断用户是否已在群聊中
	var groupMember model.ImGroupMember
	if err := groupMember.GetImGroupMember(&model.ImGroupMember{UserId: uint(in.UserId)}); err != nil {
		return nil, fmt.Errorf("查询群成员失败：%v", err)
	}
	if groupMember.Id != 0 {
		return nil, fmt.Errorf("当前用户已在群聊中")
	}

	// 添加群成员
	groupMember = model.ImGroupMember{
		GroupId:        in.GroupId,
		UserId:         uint(in.UserId),
		Role:           1,
		MemberNickname: in.MemberNickname,
		JoinedAt:       time.Now(),
		CreatedAt:      time.Now(),
	}
	if err := groupMember.Create(); err != nil {
		return nil, fmt.Errorf("添加群成员失败：%v", err)
	}

	// 更新群成员数量
	group.MemberCount++
	if err := config.DB.Model(&model.ImGroup{}).Where("group_id = ?", group.GroupId).
		Update("member_count", group.MemberCount).Error; err != nil {
		return nil, fmt.Errorf("更新群聊成员数量失败：%v", err)
	}

	return &group, nil
}

// 获取群聊消息
func GetGroupMessage(_ context.Context, in *chat.GetGroupMessageReq) ([]*chat.GroupMessage, error) {
	// 查询会话消息
	var imMessage model.ImMessage
	imMessages, err := imMessage.GetGroupMessages(&model.ImMessage{ToTargetId: in.GroupId})
	if err != nil {
		return nil, fmt.Errorf("查询会话消息失败：%w", err)
	}

	// 转换为pb消息
	var imMessageList []*chat.GroupMessage
	for _, message := range imMessages {
		list := chat.GroupMessage{
			Id:             message.Id,
			ConversationId: message.ConversationId,
			FormUserId:     message.FormUserId,
			Role:           message.Role,
			MemberNickname: message.MemberNickname,
			ToTargetId:     message.ToTargetId,
			Content:        message.Content,
			MessageType:    message.MessageType,
			SendTime:       message.SendTime,
		}
		imMessageList = append(imMessageList, &list)
	}
	return imMessageList, nil
}

// 获取群成员
func GetGroupMember(_ context.Context, in *chat.GetGroupMemberReq) ([]*chat.GroupMember, error) {
	// 查询群成员
	var groupMember model.ImGroupMember
	groupMembers, err := groupMember.GetGroupMember(&model.ImGroupMember{GroupId: in.GroupId})
	if err != nil {
		return nil, fmt.Errorf("查询群成员失败：%v", err)
	}

	// 转换为pb格式
	var groupMemberList []*chat.GroupMember
	for _, member := range groupMembers {
		list := chat.GroupMember{
			UserId:   int64(member.UserId),
			Role:     int64(member.Role),
			JoinTime: member.JoinedAt.Format("2006-01-02 15:04:05"),
		}
		groupMemberList = append(groupMemberList, &list)
	}
	return groupMemberList, nil
}

// 查询用户所在群聊
func GetUserGroups(_ context.Context, in *chat.GetUserGroupsReq) ([]*chat.Group, error) {
	// 查询用户所在群聊
	var groupMember model.ImGroupMember
	groupIds, err := groupMember.GetUserGroups(&model.ImGroupMember{UserId: uint(in.UserId)})
	if err != nil {
		return nil, fmt.Errorf("查询用户所在群聊失败：%v", err)
	}
	// 转换为pb格式
	var groupList []*chat.Group
	for _, group := range groupIds {
		list := chat.Group{
			GroupId: group.GroupId,
		}
		groupList = append(groupList, &list)
	}
	return groupList, nil
}

// 聊天室推荐
func ChatRoomRecommend(_ context.Context, in *chat.ChatRoomRecommendReq) ([]*chat.RecommendedChatRoom, error) {
	// 并行获取多种推荐源的聊天室
	// 基于好友推荐：获取用户好友加入的群组
	friendGroups, _ := getFriendBasedRecommendations(int64(in.UserId))
	// 热门推荐：获取当前热门的群组
	popularGroups, _ := getPopularRecommendations(5)
	// 新群推荐：获取新创建的公开群组
	newGroups, _ := getNewRecommendations(int64(in.UserId))

	// 合并推荐结果，使用map去重
	allRecommendations := make(map[int64]*chat.RecommendedChatRoom)

	// 将不同来源的推荐结果合并到map中
	mergeRecommendations(allRecommendations, friendGroups)
	mergeRecommendations(allRecommendations, popularGroups)
	mergeRecommendations(allRecommendations, newGroups)

	// 将mao转换为切片
	var recommendations []*chat.RecommendedChatRoom
	for _, room := range allRecommendations {
		recommendations = append(recommendations, room)
	}

	// 按推荐分数降序排序（分数高的优先）
	sort.Slice(recommendations, func(i, j int) bool {
		return recommendations[i].Score > recommendations[j].Score
	})

	// 限制返回数量，确保不超过请求的限制
	if len(recommendations) > 5 {
		recommendations = recommendations[:5]
	}

	return recommendations, nil
}

// getFriendBasedRecommendations 基于好友的推荐
// 推荐逻辑: 推荐用户好友加入但用户自己还未加入的群组
// 分数计算: 基础分0.7 + 每个共同好友0.1分
func getFriendBasedRecommendations(userID int64) ([]*chat.RecommendedChatRoom, error) {
	// 从数据库获取公开群组列表（排除用户已加入的）
	var groupMember model.ImGroup
	groups, err := groupMember.GetFriendJoinedGroups(uint64(userID))
	if err != nil {
		return nil, fmt.Errorf("获取热门群聊失败：%v", err)
	}

	var recommendations []*chat.RecommendedChatRoom
	// 遍历每个群组，计算推荐分数
	for _, group := range groups {
		// 获取群组成员数量
		memberCount, err := groupMember.GetGroupMemberCount(group.GroupId)
		if err != nil {
			return nil, fmt.Errorf("查询群成员数量失败：%v", err)
		}
		// 获取用户在该群组中的好友数量
		friendCount, err := groupMember.GetUserFriendCountInGroup(uint64(userID), group.GroupId)
		if err != nil {
			return nil, fmt.Errorf("查询用户好友数量失败：%v", err)
		}

		// 构建推荐对象
		recommendation := &chat.RecommendedChatRoom{
			GroupId:     uint64(group.Id),
			Name:        group.GroupName,
			Avatar:      group.GroupAvatar,
			MemberCount: uint64(memberCount),
			MaxMembers:  uint64(group.MaxMembers),
			OwnerId:     uint64(group.OwnerId),
			CreatedAt:   group.CreatedAt.Format("2006-01-02 15:04:05"),
			Score:       float32(0.7 + float64(friendCount)*0.1), // 基础分0.7 + 每个好友0.1分
			Reason:      "你的好友也在这里",
			FriendCount: uint64(friendCount),
		}
		recommendations = append(recommendations, recommendation)
	}

	return recommendations, nil
}

// getPopularRecommendations 热门推荐
// 推荐逻辑: 基于群组成员数量和活跃度的热门群组
// 分数计算: 成员比例分数(0-0.6) + 新鲜度分数(0-0.4)
func getPopularRecommendations(limit int) ([]*chat.RecommendedChatRoom, error) {
	// 从数据库获取公开群组列表（排除用户已加入的）
	var groupMember model.ImGroup
	groups, err := groupMember.GetHotGroups(limit)
	if err != nil {
		return nil, fmt.Errorf("获取热门群聊失败：%v", err)
	}

	var recommendations []*chat.RecommendedChatRoom
	// 遍历每个群组，计算热度分数
	for _, group := range groups {
		// 获取群组成员数量
		memberCount, err := groupMember.GetGroupMemberCount(group.GroupId)
		if err != nil {
			return nil, fmt.Errorf("查询群成员数量失败：%v", err)
		}

		// 计算热度分数（综合考虑成员比例和创建时间）
		popularityScore := calculatePopularityScore(group, int(memberCount))

		// 构建推荐对象
		recommendation := &chat.RecommendedChatRoom{
			GroupId:     uint64(group.Id),
			Name:        group.GroupName,
			Avatar:      group.GroupAvatar,
			MemberCount: uint64(memberCount),
			MaxMembers:  uint64(group.MaxMembers),
			OwnerId:     uint64(group.OwnerId),
			CreatedAt:   group.CreatedAt.Format("2006-01-02 15:04:05"),
			Score:       float32(popularityScore),
			Reason:      "热门聊天室",
			FriendCount: 0,
		}
		recommendations = append(recommendations, recommendation)
	}

	return recommendations, nil
}

// getNewRecommendations 新群推荐
// 推荐逻辑: 推荐新创建的公开群组
// 分数计算: 基于创建时间的新鲜度分数
func getNewRecommendations(userID int64) ([]*chat.RecommendedChatRoom, error) {
	// 从数据库获取公开群组列表（排除用户已加入的）
	var groupMember model.ImGroup
	groups, err := groupMember.GetPublicGroups(uint64(userID))
	if err != nil {
		return nil, fmt.Errorf("获取热门群聊失败：%v", err)
	}

	var recommendations []*chat.RecommendedChatRoom
	// 遍历每个群组，计算新鲜度分数
	for _, group := range groups {
		// 获取群组成员数量
		memberCount, err := groupMember.GetGroupMemberCount(group.GroupId)
		if err != nil {
			return nil, fmt.Errorf("查询群成员数量失败：%v", err)
		}

		// 计算基于创建时间的新鲜度分数
		freshnessScore := calculateFreshnessScore(group)

		// 构建推荐对象
		recommendation := &chat.RecommendedChatRoom{
			GroupId:     uint64(group.Id),
			Name:        group.GroupName,
			Avatar:      group.GroupAvatar,
			MemberCount: uint64(memberCount),
			MaxMembers:  uint64(group.MaxMembers),
			OwnerId:     uint64(group.OwnerId),
			CreatedAt:   group.CreatedAt.Format("2006-01-02 15:04:05"),
			Score:       float32(freshnessScore),
			Reason:      "新创建的聊天室",
			FriendCount: 0,
		}
		recommendations = append(recommendations, recommendation)
	}
	return recommendations, nil
}

// calculatePopularityScore 计算热度分数
// 分数构成:
//   - 成员比例分数: 0-0.6分（成员数/最大成员数）
//   - 新鲜度分数: 0-0.4分（30天内线性衰减）
//
// 总分范围: 0-1.0分
func calculatePopularityScore(group *model.ImGroup, memberCount int) float64 {
	// 成员比例分数 (0-0.6)
	// 计算当前成员数占最大成员数的比例
	memberRatio := float64(memberCount) / float64(group.MaxMembers)
	memberScore := 0.6 * memberRatio

	// 新鲜度分数 (0-0.4)
	// 计算群组创建至今的天数
	daysSinceCreation := time.Since(group.CreatedAt).Hours() / 24
	// 30天内线性衰减，超过30天分数为0
	freshnessScore := 0.4 * (1 - (daysSinceCreation / 30))

	// 确保新鲜度分数不为负数
	if freshnessScore < 0 {
		freshnessScore = 0
	}

	// 返回总分
	return memberScore + freshnessScore
}

// calculateFreshnessScore 计算新鲜度分数
// 评分标准:
//   - 24小时内创建: 0.9分
//   - 1周内创建: 0.7分
//   - 1周以上: 0.5分
func calculateFreshnessScore(group *model.ImGroup) float64 {
	// 计算群组创建至今的小时数
	hoursSinceCreation := time.Since(group.CreatedAt).Hours()

	// 根据创建时间给予不同的分数
	if hoursSinceCreation < 24 {
		return 0.9 // 24小时内创建的，给予最高分
	} else if hoursSinceCreation < 168 { // 168小时 = 7天
		return 0.7 // 一周内创建的，给予中等分数
	} else {
		return 0.5 // 一周以上创建的，给予基础分数
	}
}

// mergeRecommendations 合并推荐结果
// 功能: 将源推荐列表合并到目标map中，处理重复推荐项
// 去重策略: 如果同一群组出现在多个推荐源中，保留分数最高的推荐
func mergeRecommendations(target map[int64]*chat.RecommendedChatRoom, source []*chat.RecommendedChatRoom) {
	// 遍历源推荐列表
	for _, rec := range source {
		// 检查该群组是否已存在于目标map中
		if existing, exists := target[int64(rec.GroupId)]; exists {
			// 如果已存在，比较分数，保留分数更高的推荐
			if rec.Score > existing.Score {
				target[int64(rec.GroupId)] = rec
			}
		} else {
			// 如果不存在，直接添加到目标map
			target[int64(rec.GroupId)] = rec
		}
	}
}
